/**
  ETFAna project, Anyang Normal University && IMP-CAS
  \class ETFT0Array
  \brief The plastic scintillator array next to T0 in F1, for pos detection
  \author SUN Yazhou, asia.rabbit@163.com
  \since 2023-12-19
  \date 2023-12-19 last modified
  \attention
  changelog
  <table>
  <tr>  <th>Date         <th>Author      <th>Description                   </tr>
  <tr>  <td>2023-12-19   <td>Asia Sun    <td>file created                  </tr>
  </table>

  \copyright Copyright (c) 2021-2024 Anyang Normal U. && IMP-CAS with LGPLv3 LICENSE
*/

#include <iostream>
#include <TTree.h>
#include <TClonesArray.h>
#include "ETFT0Array.h"
#include "ETFPlaHit.h"
#include "ETFHPTDCCh.h"
#include "ETFRawChannel.h"
#include "ETFMsg.h"

using std::cout;
using std::endl;

ETFT0Array::ETFT0Array(const char *name, int ns, double width, double length)
: ETFTOFWall(name, ns, width, length), fStripIdM(-1){}

ETFT0Array::~ETFT0Array(){}

// initialize the detector
void ETFT0Array::Initialize(){
  ETFTOFWall::Initialize();
  fStripIdM = -1;
  fXF1 = -999.;
} // end member function Initialize

void ETFT0Array::Register(){
  ETFTOFWall::Register();
  fTree->Branch("xf1", &fXF1, "xf1/D");
} // end member function Register

void ETFT0Array::AddHit(const ETFRawChannel *ch, int stripId, int udvh){
  ETFPlaHit *hit = nullptr;
  for(auto p : *fHits){
    ETFPlaHit *h = static_cast<ETFPlaHit *>(p);
    if(h->GetStripId() == stripId){ // old strip
      hit = h; continue;
    } // end if
  } // end for
  if(!hit && ch->IsT()){ // create a new strip: Q ch does not trigger this
    fStripIdMap[stripId] = fHits->GetEntriesFast();
    hit = static_cast<ETFPlaHit *>(fHits->ConstructedAt(fHits->GetEntriesFast()));
    hit->Initialize();
    hit->SetName(ETFMsg::Form("%s_StripId%d", GetName(), stripId));
    hit->SetStripId(stripId);
    hit->SetLength(LENGTH);
    hit->SetDelay(fDelay + fDelayStr[stripId]);

    // assign strip position
    // const int id0 = stripId + 1;
    // int id = -1;
    // if(id0 >= 1  && id0 <= 17) id = 3*id0 - 2;
    // else if(id0 >= 18 && id0 <= 34) id = 3*(id0-18) + 2;
    // else if(id0 >= 35 && id0 <= 50) id = 3*(id0-34);
    // else ETFMsg::Error("ETFT0Array", "AddHit: Illegal strip id: %d", id0);
    // id -= 1;

    const int id = stripId/17 + stripId%17*3;
    static const double TMP = (1.-NS)/2.;
    // const double x0 = -WIDTH*(TMP + id);
    hit->SetX(-WIDTH*(TMP + id));
    hit->SetY(0.);
    hit->SetZ(0.);

    TransformToLabRef(hit);
    fIsFired = true;
  } // end if
  if(ch->IsT()) hit->SetTChannel(ch, udvh);
  else hit->SetQChannel(ch, udvh);
} // end member function AddHit

void ETFT0Array::PostAssign(){
  ETFTOFWall::PostAssign();
  Filter();
} // end member function PostAssign

// only 1 strip is supposed to be fired: this method filter the others
// it is now found that for the genuine hit the tl is earlier and tot is much larger
// compared with the secondary spurious hits
void ETFT0Array::Filter(){
  double q = 0., qm = -1.e200; // the estimator
  ETFPlaHit *tm = nullptr;
  for(TObject *b : *fHits){
    ETFPlaHit *t = static_cast<ETFPlaHit *>(b);
    if(t->fired() != 4) continue;
    const ETFHPTDCCh *tu = t->GetTChannel(0);
    const ETFHPTDCCh *td = t->GetTChannel(2);
    // 1. to be within a range of dt w.r.t. tstart4
    // if(-999. == fT0 || fabs(t->GetTime() - fT0) > 3.) continue;
    // 2. select those with earliest time and reasonably large tot
    double ttu = tu->tot(), ttd = td->tot();
    if(-999. == ttu) ttu = 5.; // maybe too small to be measurable
    if(-999. == ttd) ttd = 5.; // maybe too small to be measurable
    q = (ttu + ttd)*0.01 - t->time(); // the larger, the better
    if(q > qm){
      qm = q;
      tm = t;
    } // end if
  } // end for over t0arr strips

  if(tm){
    tm->SetOptimal(); // mark as the chosen one
    fStripIdM = tm->stripId();
    fXF1 = tm->x();
  } // end if
} // end member function Filter

ETFPlaHit *ETFT0Array::OptimalHit() const{
  if(-1 == fStripIdM) return nullptr;
  return GetStrip(fStripIdM);
} // end member function OptimalHit

void ETFT0Array::Print(){
  ETFTOFWall::Print();
  cout << "Optimal Hit Strip: " << fStripIdM << endl;
} // end member function Print
